/*
 * EuropeanaItem.java - europeana4j
 * (C) 2011 Digibis S.L.
 */
package com.digibis.europeana4j;

import com.digibis.europeana4j.adv.EuropeanaComplexQuery;
import java.io.IOException;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.lang.reflect.Type;
import java.net.URLEncoder;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonWriter;

/**
 * A EuropeanaItem is the metadata of a work record provided by Europeana.
 *
 * @author Andres Viedma Pelaez
 */
public class EuropeanaItem {

    private List<String> title;
    private String link;
    private String guid;
    private String description;
    private String enclosure;
    // dcterms:
    private List<String> isPartOf;
    // europeana:
    private String type;
    private List<String> year;
    private List<String> language;
    private List<String> provider;
    private List<String> dataProvider;
    private List<String> rights;
    // enrichment:
    private List<String> period_begin;
    private List<String> period_end;
    private List<String> place_latitude;
    private List<String> place_longitude;
    private List<String> period_term;
    private List<String> period_label;
    private List<String> place_term;
    private List<String> place_label;
    private List<String> concept_term;
    private List<String> concept_label;
    
    private List<String> europeanaCollectionName;
    private List<String> dcCreator;
    
    private String id;
    private Integer index;
    private Integer completeness;
    
    // own property
    private String savedBestThumbnail;

    public EuropeanaItem() {
    }

    /*
     ********* CONVENIENCE METHODS **********
     */
    /**
     * Returns true if the item is classified as textual material
     * @return 
     */
    public boolean isText() {
        return EuropeanaComplexQuery.TYPE.TEXT.equals(this.type);
    }

    /**
     * Returns true if the item is classified as image material
     * @return 
     */
    public boolean isImage() {
        return EuropeanaComplexQuery.TYPE.IMAGE.equals(this.type);
    }

    /**
     * Returns true if the item is classified as sound material
     * @return 
     */
    public boolean isSound() {
        return EuropeanaComplexQuery.TYPE.SOUND.equals(this.type);
    }

    /**
     * Returns true if the item is classified as video material
     * @return 
     */
    public boolean isVideo() {
        return EuropeanaComplexQuery.TYPE.VIDEO.equals(this.type);
    }
    
    /**
     * Returns true if the item is classified as 3D material
     * @return 
     */
    public boolean is3D() {
        return EuropeanaComplexQuery.TYPE._3D.equals(this.type);
    }

    /**
     * Returns the main creator of the item
     * @return 
     */
    public String getCreator() {
        if (this.description == null) {
            return null;
        }

        int iUno = this.description.lastIndexOf(';');
        if (iUno < 0) {
            return null;
        }
        String quitar2Derechos = this.description.substring(0, iUno);
        int iDos = quitar2Derechos.lastIndexOf(';');
        if (iDos < 0) {
            return null;
        }
        quitar2Derechos = quitar2Derechos.substring(0, iDos);

        return quitar2Derechos;
    }

    /**
     * Returns the URL of the item thumbnail. This is the thumbnail generated by
     * Europeana.
     * @return 
     */
    public String getThumbnailURL() {
        try {
            String encodedThumb = "";
            if (this.enclosure != null) {
                encodedThumb = URLEncoder.encode(this.enclosure, "UTF-8");
            }
            return "http://europeanastatic.eu/api/image?uri=" + encodedThumb;

        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Returns the URL of the item thumbnail. If the item does not provide a
     * thumbnail, it returns the URL of the thumbnail of the type of item.
     * @return 
     */
    public String getThumbnailOrTypeURL() {
        try {
            String encodedThumb = "";
            if (this.enclosure != null) {
                encodedThumb = URLEncoder.encode(this.enclosure, "UTF-8");
            }
            return "http://europeanastatic.eu/api/image?uri=" + encodedThumb + "&type=" + this.getType();

        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Returns the URL of the item thumbnail, as provided by the data provider.
     * The URL provided by getThumbnailURL and getThumbnailOrTypeURL is expected
     * to be more stable than this one. But in the other hand, this one might be
     * larger than the other.
     * @return 
     */
    public String getOriginalThumbnailURL() {
        return this.enclosure;
    }

    /**
     * This property allows the user to choose the "best" thumbnail between the
     * original one as provided by the data provider, and the one generated by
     * Europeana.
     * @return 
     */
    public String getSavedBestThumbnail() {
        return savedBestThumbnail;
    }

    public void setSavedBestThumbnail(String savedBestThumbnail) {
        this.savedBestThumbnail = savedBestThumbnail;
    }

    public boolean hasBestThumbnailSaved() {
        return ((this.savedBestThumbnail != null) && (this.savedBestThumbnail.length() > 0));
    }

    /**
     * Returns the "best" thumbnail URL. If the user has chosen a thumbnail
     * (get/setSavedBestThumbnail), it returns that one, otherwise ir returns
     * the one provided by Europeana.
     * @return 
     */
    public String getBestThumbnail() {
        if (this.hasBestThumbnailSaved()) {
            return this.savedBestThumbnail;
        } else {
            return this.getThumbnailOrTypeURL();
        }
    }

    /**
     * Returns the object unique identifier.
     * @return 
     */
    public String getObjectIdentifier() {
        String part0 = this.getObjectURL();
        if (part0 == null) {
            return null;
        }
        int iPart = part0.lastIndexOf('/');
        if (iPart < 0) {
            return null;
        } else {
            part0 = part0.substring(iPart + 1);
            iPart = part0.indexOf('.');
            if (iPart > 0) {
                part0 = part0.substring(0, iPart);
            }
            return part0;
        }
    }

    /**
     * Returns the URL of the digital object in Europeana.
     * @return 
     */
    public String getObjectURL() {
        return this.getGuid();
    }

    /**
     * Returns the URL of the digital object in Europeana in SRW format. This
     * URL provides additional information of the item, not present in this
     * EuropeanaItem object.
     * @return 
     */
    public String getSRWURL() {
        return getSRWURL(this.guid);
    }
    
    /**
     * Returns the URL of the digital object in Europeana in SRW format. This
     * URL provides additional information of the item, not present in europeana String.
     * @return 
     */
    protected static String getSRWURL(String europeanaGuid) {
        int idx = europeanaGuid.lastIndexOf('.');
        if (idx != -1) {
            return europeanaGuid.substring(0, idx) + ".srw";
        } else {
            return europeanaGuid + ".srw";
        }
    }

    /**
     * Returns a JSON representation of this item. This JSON representation will
     * be slightly different to the one provided by the Europeana API, with no
     * namespaces information.
     * @return 
     */
    public String toJSON() {
        Gson gson = new Gson();
        return gson.toJson(this);
    }

    /**
     * Writes a JSON representation of this item. This JSON representation will
     * be slightly different to the one provided by the Europeana API, with no
     * namespaces information.
     * @param out 
     * @throws IOException 
     */
    public void toJSON(Writer out) throws IOException {
        Gson gson = new Gson();
        JsonWriter out2 = new JsonWriter(out);
        gson.toJson(this, EuropeanaItem.class, out2);
        out2.flush();
    }

    /**
     * Creates an item from a JSON representation. The expected JSON
     * representation will be slightly different to the one provided by the
     * Europeana API, with no namespaces information.
     * @param json
     * @return  
     */
    public static EuropeanaItem loadJSON(String json) {
        Gson gson = new Gson();
        return gson.fromJson(json, EuropeanaItem.class);
    }

    /**
     * Creates an item from a JSON representation. The expected JSON
     * representation will be slightly different to the one provided by the
     * Europeana API, with no namespaces information.
     * @param json
     * @return  
     */
    public static EuropeanaItem loadJSON(Reader json) {
        Gson gson = new Gson();
        return gson.fromJson(json, EuropeanaItem.class);
    }

    /**
     * Creates a list of items from a JSON representation. The expected JSON
     * representation will be slightly different to the one provided by the
     * Europeana API, with no namespaces information.
     * @param json 
     * @return 
     */
    public static List<EuropeanaItem> loadJSONList(String json) {
        Gson gson = new Gson();
        Type collectionType = new TypeToken<List<EuropeanaItem>>() {
        }.getType();
        return gson.fromJson(json, collectionType);
    }

    /**
     * Creates a list of items from a JSON representation. The expected JSON
     * representation will be slightly different to the one provided by the
     * Europeana API, with no namespaces information.
     * @param json
     * @return  
     */
    public static List<EuropeanaItem> loadJSONList(Reader json) {
        Gson gson = new Gson();
        Type collectionType = new TypeToken<List<EuropeanaItem>>() {
        }.getType();
        return gson.fromJson(json, collectionType);
    }

    /*
     ********* DIRECT PROPERTY GETTERS / SETTERS **********
     */
    public List<String> getTitle() {
        return title;
    }

    public void setTitle(List<String> title) {
        this.title = title;
    }

    public String getLink() {
        return link;
    }

    public void setLink(String link) {
        this.link = link;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getEnclosure() {
        return enclosure;
    }

    public void setEnclosure(String enclosure) {
        this.enclosure = enclosure;
    }

    public String getGuid() {
        return guid;
    }

    public void setGuid(String guid) {
        this.guid = guid;
    }

    public List<String> getYear() {
        return year;
    }

    public void setYear(List<String> year) {
        this.year = year;
    }

    public List<String> getLanguage() {
        return language;
    }

    public void setLanguage(List<String> language) {
        this.language = language;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public List<String> getProvider() {
        return provider;
    }

    public void setProvider(List<String> provider) {
        this.provider = provider;
    }

    public List<String> getDataProvider() {
        return dataProvider;
    }

    public void setDataProvider(List<String> dataProvider) {
        this.dataProvider = dataProvider;
    }

    public List<String> getRights() {
        return rights;
    }

    public void setRights(List<String> rights) {
        this.rights = rights;
    }

    public List<String> getPeriod_begin() {
        return period_begin;
    }

    public void setPeriod_begin(List<String> period_begin) {
        this.period_begin = period_begin;
    }

    public List<String> getPeriod_end() {
        return period_end;
    }

    public void setPeriod_end(List<String> period_end) {
        this.period_end = period_end;
    }

    public List<String> getPlace_latitude() {
        return place_latitude;
    }

    public void setPlace_latitude(List<String> place_latitude) {
        this.place_latitude = place_latitude;
    }

    public List<String> getPlace_longitude() {
        return place_longitude;
    }

    public void setPlace_longitude(List<String> place_longitude) {
        this.place_longitude = place_longitude;
    }

    public List<String> getPeriod_term() {
        return period_term;
    }

    public void setPeriod_term(List<String> period_term) {
        this.period_term = period_term;
    }

    public List<String> getPeriod_label() {
        return period_label;
    }

    public void setPeriod_label(List<String> period_label) {
        this.period_label = period_label;
    }

    public List<String> getPlace_term() {
        return place_term;
    }

    public void setPlace_term(List<String> place_term) {
        this.place_term = place_term;
    }

    public List<String> getPlace_label() {
        return place_label;
    }

    public void setPlace_label(List<String> place_label) {
        this.place_label = place_label;
    }

    public List<String> getConcept_term() {
        return concept_term;
    }

    public void setConcept_term(List<String> concept_term) {
        this.concept_term = concept_term;
    }

    public List<String> getConcept_label() {
        return concept_label;
    }

    public void setConcept_label(List<String> concept_label) {
        this.concept_label = concept_label;
    }

    public List<String> getIsPartOf() {
        return isPartOf;
    }

    public void setIsPartOf(List<String> isPartOf) {
        this.isPartOf = isPartOf;
    }

    /**
     * @return the index
     */
    public Integer getIndex() {
        return index;
    }

    /**
     * @param index the index to set
     */
    public void setIndex(Integer index) {
        this.index = index;
    }

    /**
     * @return the completeness
     */
    public Integer getCompleteness() {
        return completeness;
    }

    /**
     * @param completeness the completeness to set
     */
    public void setCompleteness(Integer completeness) {
        this.completeness = completeness;
    }

    /**
     * @return the europeanaCollectionName
     */
    public List<String> getEuropeanaCollectionName() {
        return europeanaCollectionName;
    }

    /**
     * @param europeanaCollectionName the europeanaCollectionName to set
     */
    public void setEuropeanaCollectionName(List<String> europeanaCollectionName) {
        this.europeanaCollectionName = europeanaCollectionName;
    }

    /**
     * @return the id
     */
    public String getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(String id) {
        this.id = id;
    }

    /**
     * @return the dcCreator
     */
    public List<String> getDcCreator() {
        return dcCreator;
    }

    /**
     * @param dcCreator the dcCreator to set
     */
    public void setDcCreator(List<String> dcCreator) {
        this.dcCreator = dcCreator;
    }
}
